#include "stc.h"
#include<time.h>
#include "LargePhoneBook.h"

// Model
struct PhoneBook
{
	int _id;
	char name[17];
	char phone[17];
	struct PhoneBook* next;
	struct PhoneBook* prev;
};

struct NameIndex
{
	char name[17];
	struct PhoneBook* index;
	struct NameIndex* left;
	struct NameIndex* right;
};

struct IdIndex
{
	int id;
	struct PhoneBook* index;
	struct IdIndex* left;
	struct IdIndex* right;
};

struct  PhoneBook list[20000];
struct NameIndex nameIndex[20000];
struct IdIndex idIndex[20000];
int stop = 0;
int times = 1;
int key = 0;

// View
void createOptionMenu()
{
	PutStr("\n\nSTC PhoneBook");
	PutStr("\n1. Add");
	PutStr("\n2. Delete by name");
	PutStr("\n3. Delete by id");
	PutStr("\n4. Search by name");
	PutStr("\n5. Search by id");
	PutStr("\n6. List by name");
	PutStr("\n7. List by id");
	PutStr("\n------------");
	PutStr("\n0. Exit");
}

int lenStr(char *str);

void displayPhoneBook(PhoneBook *_phone)
{
	PutStr("\n");
	PutStr(_phone->name);
	for(int i = 0; i < 18-lenStr(_phone->name); i++)
		PutStr(" ");
	PutInt(_phone->_id);
	if(_phone->_id < 10000)
		PutStr(" ");
	PutStr("    ");
	PutStr(_phone->phone);
}

// Control
void copyStr(char *str1, char *str2)
{
	while(*str2 != 0)
	{
		*str1 = *str2;
		str1++;
		str2++;
	}
	*str1 = '\0';
}

char* getStr()
{
	char* input = new char[17];
	char c = 0;
	int count = 0;
	char arrInput[17];
	while(true)
	{
		c = GetChar();
		if (c != 13)
		{
			arrInput[count] = c;
			PutChar(arrInput[count]);
			count++;
		}
		if(c == 8)
		{
			if(count > 0)
			{
				PutStr(" \b");
				count = count - 2;
			}
		}

		if((c == 13 && count > 0) || count >= 16)
			break;
	}
	arrInput[count] = '\0';
	copyStr(input, arrInput);
	return input;
}

int lenStr(char *str)
{
	int len = 0;
	while(*str != 0)
	{
		len++;
		str++;
	}

	return len;
}

int cmpStr(char *str1, char *str2)
{
	while(*str1 != 0 && *str2 != 0)
	{
		if(*str1 != *str2)
		{
			if(*str1 >= 65 && *str1 <= 122 && *str2 >= 65 && *str2 <= 122)
			{
				if(((*str1 >= 65 && *str1 <= 90) && (*str2 >= 65 && *str2 <= 90)) || ((*str2 >= 65 && *str2 <= 90) && (*str1 >= 65 && *str1 <= 90)))
					return *str1-*str2;
				else if(((*str1 >= 97 && *str1 <= 122) && (*str2 >= 97 && *str2 <= 122)) || ((*str2 >= 97 && *str2 <= 122) && (*str1 >= 97 && *str1 <= 122)))
					return *str1-*str2;
				else if(*str1 >= 97)
				{
					if(*str1-32-*str2 == 0)
						return 1;
					else
						return *str1-32-*str2;
				}
				else
				{
					if(*str1+32-*str2 == 0)
						return -1;
					else
						return *str1+32-*str2;
				}
			}
			else
				return *str1-*str2;
		}
		str1++;
		str2++;
	}
	return lenStr(str1)-lenStr(str2);
}

int InsertName(struct NameIndex* root, char* name, PhoneBook *data)
{
	if(root == NULL)
	{
		root = new NameIndex;
		copyStr(root->name, name);
		root->index = data;
		root->left = NULL;
		root->right = NULL;
	}
	else
	{
		if(cmpStr(root->name, name) > 0)
		{
			if(root->left != NULL)
				InsertName(root->left, name, data);
			else
			{
				root->left = new NameIndex;
				copyStr(root->left->name, name);
				root->left->index = data;
				root->left->left = NULL;
				root->left->right = NULL;
			}
		}
		else if(cmpStr(root->name, name) < 0)
		{
			if(root->right != NULL)
				InsertName(root->right, name, data);
			else
			{
				root->right = new NameIndex;
				copyStr(root->right->name, name);
				root->right->index = data;
				root->right->left = NULL;
				root->right->right = NULL;
			}
		}
	}
	return 1;
}

void DeleteNodeName(NameIndex *&tree);

void DeleteName(NameIndex *&tree, char *name)
{
	if(tree == NULL)
		return;
	if(cmpStr(tree->name, name) > 0)
		DeleteName (tree->left, name);
	else if(cmpStr(tree->name, name) < 0)
		DeleteName (tree->right, name);
	else
		DeleteNodeName(tree);
}

void DeleteNodeName(NameIndex *&tree)
{
	NameIndex *temp;

	temp = tree;
	if (tree->left == NULL)
	{
		tree = tree->right;
		delete temp;
	}
	else if (tree->right == NULL)
	{
		tree = tree->left;
		delete temp;
	}
	else
	{
		temp = tree->left; 
		while (temp->right != NULL)
			temp = temp->right; 
		copyStr(tree->name, temp->name);
		tree->index = temp->index;
		DeleteName(tree->left, temp->name);
	}
}

PhoneBook* GetDataName(struct NameIndex* root, char *name)
{
	if(root == NULL)
		return NULL;
	if(cmpStr(root->name, name) > 0)
		GetDataName (root->left, name);
	else if(cmpStr(root->name, name) < 0)
		GetDataName (root->right, name);
	else
	{
		return root->index;
	}
}

int InsertId(struct IdIndex* root, int _id, PhoneBook *data)
{
	if(root == NULL)
	{
		root = new IdIndex;
		root->id = _id;
		root->index = data;
		root->left = NULL;
		root->right = NULL;
	}
	else
	{
		if(root->id > _id)
		{
			if(root->left != NULL)
				InsertId(root->left, _id, data);
			else
			{
				root->left = new IdIndex;
				root->left->id = _id;
				root->left->index = data;
				root->left->left = NULL;
				root->left->right = NULL;
			}
		}
		else if(root->id < _id)
		{
			if(root->right != NULL)
				InsertId(root->right, _id, data);
			else
			{
				root->right = new IdIndex;
				root->right->id = _id;
				root->right->index = data;
				root->right->left = NULL;
				root->right->right = NULL;
			}
		}
	}
	return 1;
}

PhoneBook* GetDataId(struct IdIndex* root, int _id)
{
	if(root == NULL)
		return NULL;
	if(root->id > _id)
		GetDataId(root->left, _id);
	else if(root->id < _id)
		GetDataId(root->right, _id);
	else
		return root->index;
}

void DeleteNodeId(IdIndex *&tree);

void DeleteId(IdIndex *&tree, int _id)
{
	if(tree == NULL)
		return;
	if(tree->id > _id)
		DeleteId(tree->left, _id);
	else if(tree->id < _id)
		DeleteId(tree->right, _id);
	else
		DeleteNodeId(tree);
}

void DeleteNodeId(IdIndex *&tree)
{
	IdIndex *temp;

	temp = tree;
	if (tree->left == NULL)
	{
		tree = tree->right;
		delete temp;
	}
	else if (tree->right == NULL)
	{
		tree = tree->left;
		delete temp;
	}
	else
	{
		temp = tree->left; 
		while (temp->right != NULL)
			temp = temp->right; 
		tree->id = temp->id;
		tree->index = temp->index;
		DeleteId(tree->left, temp->id);
	}
}

void loadPhoneBook(PhoneBook *root, NameIndex *rootName, IdIndex *rootId)
{
	PutStr("Initing data...");
	for(int index = 1; index < 10000; index++)
	{
		struct PhoneBook* pb = new PhoneBook;
		pb->_id = initId[index];
		copyStr(pb->name, initName[index]);
		copyStr(pb->phone, initPhone[index]);
		InsertName(rootName, pb->name, pb);
		InsertId(rootId, pb->_id, pb);
	}
	ClearScreen();

}

void addPhoneBook(NameIndex *rootName, IdIndex *rootId)
{
	struct PhoneBook *book = new PhoneBook;
	while(true)
	{
		while(true)
		{
			PutStr("\nId>");
			book->_id = GetInt();
			if(book->_id < 1000 || book->_id  > 99999)
				PutStr("The PhoneBook ID has been between 1000 and 99999");
			else
				break;
		}
		PhoneBook *result = GetDataId(rootId, book->_id);
		if(result == NULL)
			break;
		else
			PutStr("The id was existed");
	}
	PutStr("Name>");
	copyStr(book->name, getStr());
	PutStr("\nNumber>");
	copyStr(book->phone, getStr());
	PutStr("\nOK");

	InsertName(rootName, book->name, book);
	InsertId(rootId, book->_id, book);
}

void deletebyName(NameIndex *rootName, IdIndex *rootId)
{
	char name[17];
	PutStr("\nName>");
	copyStr(name, getStr());
	PhoneBook *book = GetDataName(rootName, name);
	DeleteName(rootName, book->name);
	DeleteId(rootId, book->_id);
}

void deleteById(IdIndex *rootId, NameIndex *rootName)
{
	int _id;
	PutStr("\nId>");
	_id = GetInt();
	PhoneBook *book = GetDataId(rootId, _id);
	DeleteId(rootId, book->_id);
	DeleteName(rootName, book->name);
}

void searchByName(NameIndex *root)
{
	char name[17];
	PutStr("\nName>");
	copyStr(name, getStr());

	PhoneBook *result = GetDataName(root, name);
	if(result == NULL)
		PutStr("\nCan not find this name");
	else
		displayPhoneBook(result);
}

void searchById(IdIndex *root)
{
	int _id;
	PutStr("\nId>");
	_id = GetInt();
	PhoneBook *result = GetDataId(root, _id);
	if(result == NULL)
		PutStr("\nCan not find this name");
	else
		displayPhoneBook(result);
}

int inorderName(NameIndex *rootName)
{
	if(!rootName)
		return 1;
	if(rootName != NULL)
	{
		if(rootName->left != NULL)
		{
			if(inorderName(rootName->left) == 0) return 0;
		}
		if(stop <= 20*times)
		{
			displayPhoneBook(rootName->index);
			stop++;
		}
		else if(stop > 20*times)
		{
			PutStr("\nPlease enter any key to continued");
			key = GetChar();
			if(key == 8)
			{
				ClearScreen();
				return 0;
			}
			if(key != 0)
				times++;
		}
		if(rootName->right != NULL)
		{
			if(inorderName(rootName->right) == 0) return 0;
		}
	}
}

void listByName(NameIndex *rootName)
{
	stop = 0;
	times = 1;
	key = 0;
	inorderName(rootName);
}

int inorderId(IdIndex *rootId)
{
	if(!rootId)
		return 1;
	if(rootId != NULL)
	{
		if(rootId->left != NULL)
		{
			if(inorderId(rootId->left) == 0) return 0;
		}
		if(stop <= 20*times)
		{
			displayPhoneBook(rootId->index);
			stop++;
		}
		else if(stop > 20*times)
		{
			PutStr("\nPlease enter any key to continued");
			key = GetChar();
			if(key == 8)
			{
				ClearScreen();
				return 0;
			}
			if(key != 0)
				times++;
		}
		if(rootId->right != NULL)
		{
			if(inorderId(rootId->right) == 0) return 0;
		}
	}
}

void listById(IdIndex *rootId)
{
	stop = 0;
	times = 1;
	key = 0;
	inorderId(rootId);
}

void main(void)
{
	char choice = '1';
	PhoneBook* root = new PhoneBook;
	NameIndex* rootName = new NameIndex;
	IdIndex* rootId = new IdIndex;
	root->next = NULL;
	PhoneBook *first = new PhoneBook;
	first->_id = initId[0];
	copyStr(first->name, initName[0]);
	copyStr(first->phone, initPhone[0]);

	copyStr(rootName->name, first->name);
	rootName->index = first;
	rootName->left = NULL;
	rootName->right = NULL;

	rootId->id = first->_id;
	rootId->index = first;
	rootId->left = NULL;
	rootId->right = NULL;

	loadPhoneBook(root, rootName, rootId);


	while(choice != '0')
	{
		createOptionMenu();
		PutStr("\n\nCommand>");
		choice = GetChar();
		PutChar(choice);
		switch(choice)
		{
		case '1':
			addPhoneBook(rootName, rootId);
			break;
		case '2':
			deletebyName(rootName, rootId);
			break;
		case '3':
			deleteById(rootId, rootName);
			break;
		case '4':
			searchByName(rootName);
			break;
		case '5':
			searchById(rootId);
			break;
		case '6':
			listByName(rootName);
			break;
		case '7':
			listById(rootId);
			break;
		case '0':
			break;
		}
	}

	return;
}